import cv2
import base64
import numpy as np
import uvicorn
from fastapi import FastAPI, Body
from fastapi.responses import HTMLResponse
import socket

description = """
_________________
### 项目说明：

* <strong>会HttpPost协议即可调用的原则！</strong>

* 支持部署 <strong>本地</strong> 和 <strong>服务器</strong> .

* <strong>长期更新 免费开源 欢迎赞助 </strong>

### 关于作者：

* 哔哩哔哩 <https://space.bilibili.com/37887820>

* GitHub <https://github.com/81NewArk/StupidOCR>

### 
_________________
"""

app = FastAPI(
    title='StupidOCR-图标选点版',
    description=description,
    version="1.0.1",
)


@app.post("/api.TargetReconnoitre", summary='侦察图片目标', description='上传图片的Base64编码，返回每个目标的xywh和中心点', tags=['Icon点选'])
async def TargetReconnoitre(have_Ico_Image: str = Body(..., title='图片Base64', embed=True)):
    if __name__ == '__main__':
        img_data = base64.b64decode(have_Ico_Image)
        # 使用numpy数组来表示图像数据
        img_array = np.frombuffer(img_data, dtype=np.uint8)
        # 解码图像
        img = cv2.imdecode(img_array, flags=cv2.IMREAD_COLOR)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # 进行 Canny 边缘检测
        edges = cv2.Canny(gray, 50, 150)
        # 使用闭操作填充边缘内部的空洞
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
        closed = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
        # 查找轮廓
        contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # 存储每个 icon 的信息
        icons = []
        # 在原图上绘制轮廓并记录每个 icon 的信息
        for contour in contours:
            # 计算轮廓的边界框
            x, y, w, h = cv2.boundingRect(contour)
            # 计算轮廓的面积和宽高比
            area = cv2.contourArea(contour)
            aspect_ratio = float(w) / h if h != 0 else 0
            # 如果轮廓面积过小或宽高比不合适，则忽略该轮廓
            if area < 100 or aspect_ratio < 0.5 or aspect_ratio > 2:
                continue

            # 记录 icon 的信息
            icon = {
                'x': x,
                'y': y,
                'w': w,
                'h': h,
                'center_x': x + w / 2,
                'center_y': y + h / 2
            }
            icons.append(icon)

        # 将结果封装成字典格式输出
        result = {
            'icons': icons
        }
    hostname = socket.gethostname()
    ip = socket.gethostbyname(hostname)
    return {"result": result, "BiliBili": "https://space.bilibili.com/37887820",
            "supports": "http://" + ip + ":6688/support"}


@app.post("/api.IconReconnaissance", summary='Icon点选', description='上传icon图标和背景图标，返回每个目标的xywh和中心点，准确率随缘，等待更新', tags=['Icon点选'])
async def IcoReconnaissance(Icon_ImageBase64: str = Body(..., title='Icon图标Base64', embed=True),
                            BackGround_Base64: str = Body(..., title='背景图片base64', embed=True)):
    # 从base64编码的字符串读取图像数据
    background_data = base64.b64decode(BackGround_Base64)
    icon_data = base64.b64decode(Icon_ImageBase64)
    # 将图像数据解码为OpenCV的图像格式
    background = cv2.imdecode(np.frombuffer(background_data, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
    icon = cv2.imdecode(np.frombuffer(icon_data, dtype=np.uint8), cv2.IMREAD_GRAYSCALE)
    # 将icon图标转换为二值图像
    _, icon = cv2.threshold(icon, 128, 255, cv2.THRESH_BINARY)
    # 使用模板匹配技术查找icon图标在背景图片中的位置
    result = cv2.matchTemplate(background, icon, cv2.TM_CCOEFF_NORMED)
    # 找到最佳匹配的位置
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    top_left = max_loc
    bottom_right = (top_left[0] + icon.shape[1], top_left[1] + icon.shape[0])
    # 计算icon的中心点
    center_x = (top_left[0] + bottom_right[0]) // 2
    center_y = (top_left[1] + bottom_right[1]) // 2
    # 输出icon图标在背景图片上的坐标和中心点
    result = {
        'x': top_left[0],
        'y': top_left[1],
        'w': icon.shape[1],
        'h': icon.shape[0],
        'center_x': center_x,
        'center_y': center_y
    }
    hostname = socket.gethostname()
    ip = socket.gethostbyname(hostname)
    return {"result": result,
            "BiliBili": "https://space.bilibili.com/37887820", "supports": "http://" + ip + ":6688/support"}


@app.get("/support", response_class=HTMLResponse,tags=['赞助StupidOCR'],summary='打开网页：http://localhost:6688/support',include_in_schema=False)
async def support():
    return """
<html>
   <head>
    <title>赞助作者</title>
   </head>
    <body>
    <h1 align="center">给无业的作者打赏</h1>
    <h3 align="center">微信&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;支付宝</h3>
    <h1 align="center"> <img  src="" >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    <img  src="" ></h1>
    <hr>
    <h2 align="left"> GitHub： <a href="https://github.com/81NewArk/StupidOCR">https://github.com/81NewArk/StupidOCR</a></h2>
    <h2 align="left"> BiLiBiLi： <a href="https://space.bilibili.com/37887820">https://space.bilibili.com/37887820</a></h2>
    <h2 align="left"> E-Mail  ： 751247667@qq.com</h2>
    </body>
</html>
         """


if __name__ == '__main__':
    print('''

      _____   _                     _       _    ____     _____   _____  
     / ____| | |                   (_)     | |  / __ \   / ____| |  __ \ 
    | (___   | |_   _   _   _ __    _    __| | | |  | | | |      | |__) |
     \___ \  | __| | | | | | '_ \  | |  / _` | | |  | | | |      |  _  / 
     ____) | | |_  | |_| | | |_) | | | | (_| | | |__| | | |____  | | \ \ 
    |_____/   \__|  \__,_| | .__/  |_|  \__,_|  \____/   \_____| |_|  \_/
                           | |                                           
                           |_|                                           

                   开发文档：http://localhost:6688/docs
                   赞助页面：http://127.0.0.1:6688/support
                   作者逼站：https://space.bilibili.com/37887820

                   代码编写：81NewArk
                   当前版本为图标选点专版

       ''')

    uvicorn.run(app, port=6688, host="0.0.0.0")
